/*
 * This file is part of monitor_agent.
 * Copyright (c) 2018. Author: yinjia evoex123@gmail.com
 *
 * This program is free software: you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or (at your
 * option) any later version.  This program is distributed in the hope that it
 * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser
 * General Public License for more details.  You should have received a copy
 * of the GNU Lesser General Public License along with this program.  If not,
 * see <http://www.gnu.org/licenses/>.
 */

package module

import (
    "fmt"
    "monitor_agent/inc"
    "net"
    "os"
    "regexp"
    "strconv"
    "strings"
    "time"
)

type ServerConn struct {
	conn    *net.TCPConn
	host    string
	lastConnected int64
}

var ServerConnection = &ServerConn{}

func ConnectToServer(exit bool, sc *ServerConn, readChannel inc.ReaderChannel, reconnectChannel *inc.ReconnectChannel) (string,bool, *ServerConn) {
	sendHost, _ := inc.ConfObject.GetString("SendHosts")
	sendHosts := strings.Split(sendHost, ",")
	sendPort, _ := inc.ConfObject.GetString("SendPort")
	cName, _ := inc.ConfObject.GetString("ServerName")
	foundServer := false
	if sc.conn != nil {
		fmt.Println("close conn of server:" + sc.host)
		sc.conn.Close()
	}
	for i := range sendHosts {
		addr, err := net.ResolveTCPAddr("tcp", sendHosts[i]+":"+sendPort)
		fmt.Println("try to connect server:" + sendHosts[i])
		conn, err := net.DialTCP("tcp", nil, addr)
		if err != nil {
			fmt.Println(err.Error())
			if i == len(sendHosts)-1 {
				if exit {
				    fmt.Println("no collector server found! good bye.")
				    os.Exit(0)
				}
			} else {
				fmt.Println("switch to another collector server")
			}
			continue
		} else {
			foundServer = true
			sc.conn=conn
			sc.host=addr.IP.String()
			sc.lastConnected = time.Now().Unix()
			auth(sc, cName, foundServer, readChannel, reconnectChannel)
			break
		}
	}
	return cName, foundServer, sc
}

func TestServerOn() (bool) {
	sendHost, _ := inc.ConfObject.GetString("SendHosts")
	sendHosts := strings.Split(sendHost, ",")
	sendPort, _ := inc.ConfObject.GetString("SendPort")
	for i := range sendHosts {
		addr, err := net.ResolveTCPAddr("tcp", sendHosts[i]+":"+sendPort)
		fmt.Println("try to connect server:" + sendHosts[i])
		conn, err := net.DialTCP("tcp", nil, addr)
		if err != nil {

		} else {
			conn.Close()
			return true
		}
	}
	return false
}

func (c *ServerConn) Quit() error {
	return c.conn.Close()
}


func ProcessMsgLine(line string) string{
    // 解析消息
    r := regexp.MustCompile(`^([a-zA-Z0-9]+)\s+([.a-zA-Z0-9,_/\-\[\]]+)\s+(\d+\.?\d+)\s+(\S+?)((?:\s+[-_./a-zA-Z0-9]+=[-_./a-zA-Z0-9]+)*)\n$`)
    submatch := r.FindAllStringSubmatch(line, -1)
    if submatch != nil {
        fmt.Println(submatch)
        collectorName := submatch[0][1]
        metricName := submatch[0][2]
        timestamp, _ := strconv.Atoi(submatch[0][3])
        value := submatch[0][4]
        tags := submatch[0][5]
        fmt.Println("collector name:" + collectorName)
        fmt.Println("metric name:" + metricName)
        fmt.Println("timestamp:" + strconv.Itoa(timestamp))
        fmt.Println("value:" + value)
        fmt.Println("tags:" + tags)
        // 去重
        // 如果数据点是重复的，保存但不发送，保存之前的timestamp，当数据发生变化，
        // 我们不发送最后一次进来的指标的值，而是第一次进来。如果达到了去重间隔，打印该数值。
        dedupInteval := 300
        if COLLECTORS[collectorName+".so"].CollectorValues[metricName].Value == value &&
            timestamp-COLLECTORS[collectorName+".so"].CollectorValues[metricName].Timestamp < dedupInteval {
            collectorValue := inc.CollectorValue{value, true, line, COLLECTORS[collectorName+".so"].CollectorValues[metricName].Timestamp}
            COLLECTORS[collectorName+".so"].CollectorValues[metricName] = collectorValue
            fmt.Println("data duplicate, ignore:" + metricName)
            return ""
        }
        collectorValue := inc.CollectorValue{value, false, line, timestamp}
        COLLECTORS[collectorName+".so"].CollectorValues[metricName] = collectorValue
        c := COLLECTORS[collectorName+".so"] // 解决大坑map的index操作获得的变量无法取其指针
        c.LinesSent += 1
        COLLECTORS[collectorName+".so"] = c
        // disruptor下直接被消费，不用再开信道
        if inc.QueueType == 1 {
            SendSocket(ServerConnection, line, nil)
        }
        return line
    }
    return ""
}
